#include "threadPool/threadPool.h"
#include "epoll/epoll.h"
#include "net/tcpInit.h"
#include "config/config.h"
#include "log/log.h"
#include <signal.h>
#include <sys/wait.h>

// 退出管道
int exit_pipe[2];

// 退出信号处理函数
void exit_handler(int sig)
{
    // 父进程输出退出提示
    printf("server is going to exit\n");
    LOG_INFO("server is going to exit");
    // 向管道写入数据，通知子进程退出
    write(exit_pipe[0], "exit", 4);
}

int main(int argc, char *argv[])
{
    // 初始化日志
    if (log_init("log/server.log", LOG_LEVEL_DEBUG) != 0)
    {
        printf("log init failed\n");
        exit(-1);
    }
    // 创建退出管道
    socketpair(AF_LOCAL, SOCK_STREAM, 0, exit_pipe);
    // 创建父进程用于退出
    if (fork())
    {
        // 父进程关闭读端
        close(exit_pipe[1]);
        // 父进程注册信号处理函数
        signal(SIGUSR1, exit_handler);
        // 父进程等待子进程退出
        wait(NULL);
        // 父进程退出
        exit(0);
    }
    // 记录程序启动日志
    LOG_INFO("server is starting...");
    printf("server is starting...\n");
    // 子进程执行任务
    // 子进程关闭写端
    close(exit_pipe[0]);
    // 初始化线程池
    thread_pool_t pool;
    thread_pool_init(&pool, 5);
    // 记录线程池启动日志
    printf("threadpool is started with %d workers\n", pool.worker_list.worker_count);
    LOG_INFO("threadpool is started with %d workers", pool.worker_list.worker_count);
    // 读取配置
    server_config_t cfg;
    config_load("config/server.conf", &cfg);
    // TODO: 判断根路径是否存在，不存在则创建
    // 初始化tcp连接
    int sockfd = tcp_init(cfg.ip, cfg.port);
    // tcp初始化错误处理
    if (sockfd < 0)
    {
        LOG_FATAL("tcp init failed");
        // 释放线程池中的工作线程
        thread_pool_release_workers(&pool);
        exit(-1);
    }
    // 记录tcp初始化日志
    printf("tcp is initialized on %s:%s\n", cfg.ip, cfg.port);
    LOG_INFO("tcp is initialized on %s:%s", cfg.ip, cfg.port);
    // 初始化epoll
    int epfd = epoll_create_my(1);
    // epoll初始化错误处理
    if (epfd < 0)
    {
        LOG_FATAL("epoll init failed");
        // 释放线程池中的工作线程
        thread_pool_release_workers(&pool);
        exit(-1);
    }
    // 将sockfd和exit_pipe[1]添加到epoll中
    epoll_add_my(epfd, sockfd);
    epoll_add_my(epfd, exit_pipe[1]);
    // 准备一个就绪集合
    struct epoll_event ready_set[1];
    // 子进程进入事件循环
    while (1)
    {
        epoll_wait(epfd, ready_set, 1, -1);
        // 获取当前就绪的文件描述符
        int curfd = ready_set[0].data.fd;
        // 如果就绪的是sockfd，说明有新的连接请求
        if (curfd == sockfd)
        {
            // 需要在子线程中释放session
            clientSession_t *session = (clientSession_t*)malloc(sizeof(clientSession_t));
            clientSessionInit(session);
            session->netfd = accept(sockfd, NULL, NULL);
            LOG_INFO("new client connected, netfd=%d", session->netfd);
            // TODO: 初始化栈
            // 将任务添加到任务队列中
            pthread_mutex_lock(&pool.shared_resource.mutex);
            task_queue_enqueue(&pool.shared_resource.task_queue, session);
            // 通知工作线程有新任务
            pthread_cond_signal(&pool.shared_resource.cond);
            // 解锁
            pthread_mutex_unlock(&pool.shared_resource.mutex);
            continue;
        }
        // 如果就绪的是exit_pipe[1]，说明需要退出
        if (curfd == exit_pipe[1])
        {
            // 释放线程池中的工作线程
            thread_pool_release_workers(&pool);
            // 记录退出日志
            printf("threadpool is going to exit\n");
            LOG_INFO("threadpool is going to exit");
            exit(0);
        }
    }

    return 0;
}